home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / kmsg / kmsg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-11  |  12.3 KB  |  500 lines

  1. /* 
  2.  * kmsg.c --
  3.  *
  4.  *    Program that sends debugging messages to a Sprite kernel.
  5.  *    Can be used to put a kernel into the debugger, query it,
  6.  *    and resume from the debugger.
  7.  *
  8.  * Copyright 1988 Regents of the University of California
  9.  * Permission to use, copy, modify, and distribute this
  10.  * software and its documentation for any purpose and without
  11.  * fee is hereby granted, provided that the above copyright
  12.  * notice appear in all copies.  The University of California
  13.  * makes no representations about the suitability of this
  14.  * software for any purpose.  It is provided "as is" without
  15.  * express or implied warranty.
  16.  */
  17.  
  18. #ifndef lint
  19. static char rcsid[] = "$Header: /sprite/src/cmds/kmsg/RCS/kmsg.c,v 1.7 92/06/10 17:19:19 jhh Exp $ SPRITE (Berkeley)";
  20. #endif not lint
  21.  
  22. #include <errno.h>
  23. #include <host.h>
  24. #include <net.h>
  25. #include <option.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <sys/file.h>
  29. #include <kernel/dbg.h>
  30.  
  31. #include <signal.h>
  32. #include <sys/types.h>
  33. #include <sys/socket.h>
  34. #include <sys/time.h>
  35. #include <netinet/in.h>
  36. #include <netdb.h>
  37. #include <sgtty.h>
  38.  
  39. /*
  40.  * Library imports:
  41.  */
  42.  
  43. extern void panic();
  44.  
  45. /*
  46.  * Message buffers.
  47.  */
  48. static Dbg_Msg    msg;
  49. static int    msgSize;
  50. #define    REPLY_BUFFER_SIZE    4096
  51. static    char    replyBuffer[REPLY_BUFFER_SIZE];
  52. static    char    requestBuffer[DBG_MAX_REQUEST_SIZE];
  53. /*
  54.  * The decstation currently supports both kdbx and kgdb.   Since we
  55.  * are using the kgdb interface we must start the message number 
  56.  * at 0x40000000 so the debugger stub uses the right interface.
  57.  */
  58. #if defined(ds3100) || defined(ds5000)
  59. static    int    msgNum = 0x40000000;
  60. #else
  61. static    int    msgNum = 0;
  62. #endif
  63.  
  64. extern void    RecvReply();
  65.  
  66. static    struct sockaddr_in    remote;
  67. int                kdbxTimeout = 1;
  68. static    int            netSocket;
  69.  
  70. /*
  71.  *----------------------------------------------------------------------
  72.  *
  73.  * CreateSocket --
  74.  *
  75.  *    Creates a UDP socket connected to the Sprite host's kernel 
  76.  *    debugger port.
  77.  *
  78.  * Results:
  79.  *    The stream ID of the socket.
  80.  *
  81.  * Side effects:
  82.  *    None.
  83.  *
  84.  *----------------------------------------------------------------------
  85.  */
  86. int
  87. CreateSocket(spriteHostName)
  88.     char    *spriteHostName;
  89. {
  90.     int            socketID;
  91.     struct hostent     *hostPtr;
  92.  
  93.     hostPtr = gethostbyname(spriteHostName);
  94.     if (hostPtr == (struct hostent *) NULL) {
  95.     (void) fprintf(stderr, "CreateSocket: unknown host \"%s\"\n",
  96.         spriteHostName);
  97.     exit(1);
  98.     }
  99.     if (hostPtr->h_addrtype != AF_INET) {
  100.     (void) fprintf(stderr, "CreateSocket: bad address type for host %s\n", 
  101.         spriteHostName);
  102.     exit(2);
  103.     }
  104.  
  105.     socketID = socket(AF_INET, SOCK_DGRAM, 0);
  106.     if (socketID < 0) {
  107.     perror("CreateSocket: socket");
  108.     exit(3);
  109.     }
  110.  
  111.     bzero((char *) &remote, sizeof(remote));
  112.     bcopy((char *) hostPtr->h_addr, (char *) &remote.sin_addr,
  113.         hostPtr->h_length);
  114.     remote.sin_port = htons(DBG_UDP_PORT);
  115.     remote.sin_family = AF_INET;
  116.  
  117.     if (connect(socketID, (struct sockaddr *) &remote, sizeof(remote)) < 0) {
  118.     perror("CreateSocket: connect");
  119.     exit(4);
  120.     }
  121.  
  122.     return(socketID);
  123. }
  124.  
  125. /*
  126.  * ----------------------------------------------------------------------------
  127.  *
  128.  *  SendRequest --
  129.  *
  130.  *     Send a request message to the kernel.
  131.  *
  132.  * Results:
  133.  *     None.
  134.  *
  135.  * Side effects:
  136.  *     None.
  137.  * ----------------------------------------------------------------------------
  138.  */
  139. static void
  140. SendRequest(numBytes)
  141.     int    numBytes;
  142. {
  143.     Dbg_Opcode    opcode;
  144.  
  145.     msgSize = numBytes;
  146.     msgNum++;
  147.     *(int *)requestBuffer = msgNum;
  148.     bcopy((char *) &msg, requestBuffer + 4, numBytes);
  149.     if (write(netSocket, requestBuffer, numBytes + 4) < numBytes + 4) {
  150.     panic("SendRequest: Couldn't write to the kernel socket\n");
  151.     return;
  152.     }
  153.     opcode = (Dbg_Opcode) msg.opcode;
  154.     if (opcode == DBG_DETACH) {
  155.     int    dummy;
  156.     /*
  157.      * Wait for explicit acknowledgments of these packets.
  158.      */
  159.     RecvReply(opcode, 4, (char *) &dummy, (int *) NULL, 1);
  160.     }
  161. }
  162.  
  163. /*
  164.  * ----------------------------------------------------------------------------
  165.  *
  166.  *  RecvReply --
  167.  *
  168.  *     Receive a reply from the kernel.
  169.  *
  170.  * Results:
  171.  *     None.
  172.  *
  173.  * Side effects:
  174.  *     None.
  175.  * ----------------------------------------------------------------------------
  176.  */
  177.  
  178.     /* ARGSUSED */
  179. static void
  180. RecvReply(opcode, numBytes, destAddr, readStatusPtr, timeout)
  181.     Dbg_Opcode    opcode;
  182.     int        numBytes;
  183.     char    *destAddr;
  184.     int        *readStatusPtr;
  185.     int        timeout;
  186. {
  187.     int        status;
  188.     int        readMask;
  189.     struct    timeval    interval;
  190.     int        bytesRead;
  191.  
  192.  
  193.     if (numBytes + 8 > REPLY_BUFFER_SIZE) {
  194.     panic("numBytes <%d> > REPLY_BUFFER_SIZE <%d>\n",
  195.             numBytes + 8, REPLY_BUFFER_SIZE);
  196.     }
  197.     interval.tv_sec = kdbxTimeout;
  198.     interval.tv_usec = 0;
  199.     do {
  200.     if (timeout) {
  201.         int    numTimeouts;
  202.  
  203.         numTimeouts = 0;
  204.         /*
  205.          * Loop timing out and sending packets until a new packet
  206.          * has arrived.
  207.          */
  208.         do {
  209.         readMask = 1 << netSocket;
  210.         status = select(32, &readMask, (int *) NULL,
  211.             (int *) NULL, &interval);
  212.         if (status == 1) {
  213.             break;
  214.         } else if (status == -1) {
  215.             panic("RecvReply: Couldn't select on socket.\n");
  216.         } else if (status == 0) {
  217.             SendRequest(msgSize);
  218.             numTimeouts++;
  219.             if (numTimeouts % 10 == 0) {
  220.             (void) fprintf(stderr, "Timing out and resending\n");
  221.             (void) fflush(stderr);
  222.             }
  223.         }
  224.         } while (1);
  225.     }
  226.     if (opcode == DBG_GET_VERSION_STRING) {
  227.         /*
  228.          * Returning the version string returns a variable length packet.
  229.          */
  230.         bytesRead = read(netSocket, replyBuffer, numBytes);
  231.         if (bytesRead < 0) {
  232.         perror("RecvReply: Error reading socket.");
  233.         panic("exiting");
  234.         }
  235.         (void) strcpy(destAddr, (char *)(replyBuffer + 4));
  236.         return;
  237.     } else {
  238.         /*
  239.          * Normal request so just read in the message which includes
  240.          * the message number.
  241.          */
  242.         bytesRead = read(netSocket, replyBuffer, numBytes + 4);
  243.         if (bytesRead < 0) {
  244.         panic("RecvReply: Error reading socket (2).");
  245.         }
  246.         /*
  247.          * Check message number before size because it could be
  248.          * an old packet.
  249.          */
  250.         if (*(int *)replyBuffer != msgNum) {
  251.         continue;
  252.         }
  253.         if (bytesRead != numBytes + 4) {
  254.         (void) printf("RecvReply: Short read (2): op=%d exp=%d read=%d",
  255.             opcode, numBytes + 4, bytesRead);
  256.         }
  257.         if (*(int *)replyBuffer != msgNum) {
  258.         continue;
  259.         }
  260.         bcopy(replyBuffer + 4, destAddr, numBytes);
  261.         return;
  262.     }
  263.     } while (1);
  264. }
  265.  
  266. /*
  267.  * ----------------------------------------------------------------------------
  268.  *
  269.  * SendCommand --
  270.  *
  271.  *     Write the command over to the kernel.  
  272.  *
  273.  * Results:
  274.  *     None.
  275.  *
  276.  * Side effects:
  277.  *     None.
  278.  *
  279.  * ----------------------------------------------------------------------------
  280.  */
  281. void
  282. SendCommand(opcode, srcAddr, destAddr, numBytes)
  283.     Dbg_Opcode    opcode;        /* Which command */
  284.     char    *srcAddr;    /* Where to read data from */
  285.     char    *destAddr;    /* Where to write data to */
  286.     int        numBytes;    /* The number of bytes to read or write */
  287. {
  288.     msg.opcode = (short) opcode;
  289.  
  290.     switch (opcode) {
  291.     case DBG_GET_STOP_INFO:
  292.         SendRequest(sizeof(msg.opcode));
  293.         RecvReply(opcode, numBytes, destAddr, (int *) NULL, 1);
  294.         break;
  295.     case DBG_DETACH:
  296.         msg.data.pc = *(int *) srcAddr;
  297.         SendRequest(sizeof(msg.opcode) + sizeof(msg.data.pc));
  298.         break;
  299.     case DBG_GET_VERSION_STRING:
  300.         SendRequest(sizeof(msg.opcode));
  301.         RecvReply(opcode, numBytes, destAddr, (int *) NULL, 1);
  302.         break;
  303.     case DBG_REBOOT:
  304.         if (numBytes > 0) {
  305.         (void) strcpy(msg.data.reboot.string, (char *)srcAddr);
  306.         }
  307.         msg.data.reboot.stringLength = numBytes;
  308.         SendRequest(sizeof(msg.opcode) +
  309.             sizeof(msg.data.reboot.stringLength) +
  310.             msg.data.reboot.stringLength);
  311.         break;
  312.     default:
  313.         (void) printf("Unknown opcode %d\n", opcode);
  314.     }
  315. }
  316.  
  317. /*
  318.  *----------------------------------------------------------------------
  319.  *
  320.  * SendDebug --
  321.  *
  322.  *    Given a host name, this procedure sends a command to that host
  323.  *    that causes it to enter the debugger.
  324.  *
  325.  * Results:
  326.  *    0 if everything went well, 1 if there was some sort of error
  327.  *    (in this case an error message is printed).
  328.  *
  329.  * Side effects:
  330.  *    The given host will enter the debugger, if the host exists and
  331.  *    is running Sprite.
  332.  *
  333.  *----------------------------------------------------------------------
  334.  */
  335.  
  336. int
  337. SendDebug(hostName)
  338.     char *hostName;        /* Name of Sprite host. */
  339. {
  340.     Host_Entry *host;
  341.     int streamID, amtWritten;
  342.  
  343.     /*
  344.      * A debug packet contains the name of the host that is issuing
  345.      * the "enter debugger" command.  Changed 'int nameLen' to be
  346.      * 'char nameLenChar[]' in the packet struct to remove padding
  347.      * bytes which were confusing the kernel. JMS
  348.      */
  349.  
  350. #define MAX_NAME_LEN    100
  351.     struct {
  352.     Net_EtherHdr    etherHdr;
  353.     char         nameLenChar[sizeof(int)];
  354.     char        name[MAX_NAME_LEN];
  355.     } packet;
  356.  
  357.     int nameLen;
  358.     int i;
  359.  
  360.     /*
  361.      * Fill in our name in the debug packet.
  362.      */
  363.  
  364.     if (gethostname(packet.name, MAX_NAME_LEN-1) != 0) {
  365.     (void) fprintf(stderr, "Couldn't find my host name: %s\n",
  366.         strerror(errno));
  367.     return 1;
  368.     }
  369.     packet.name[MAX_NAME_LEN-1] = 0;
  370.     nameLen = strlen(packet.name);
  371.     bcopy((char *) &nameLen, packet.nameLenChar, sizeof(int));
  372.     if (strcmp(packet.name, hostName) == 0) {
  373.     (void) fprintf(stderr, "Can't send a debug packet to yourself.\n");
  374.     return 1;
  375.     }
  376.  
  377.     /*
  378.      * Set up the ethernet packet header. The source address is filled
  379.      * in by the kernel.
  380.      */
  381.     host = Host_ByName(hostName);
  382.     if (host == (Host_Entry *)NULL) {
  383.     (void) fprintf(stderr, "Unknown host: %s\n", hostName);
  384.     return 1;
  385.     }
  386.     for (i = 0; i < host->numNets; i++) {
  387.     if (host->nets[i].netAddr.type == NET_ADDRESS_ETHER) {
  388.         bcopy((char *) &host->nets[i].netAddr.address.ether,
  389.         (char *) &packet.etherHdr.destination, 
  390.         sizeof(Net_EtherAddress));
  391.         break;
  392.     }
  393.     }
  394.     packet.etherHdr.type = htons(NET_ETHER_SPRITE_DEBUG);
  395.  
  396.     streamID = open("/dev/etherSpriteDebug", O_WRONLY, 0666);
  397.     if (streamID < 0) {
  398.     (void) fprintf(stderr, "Couldn't open raw ethernet device: %s\n",
  399.         strerror(errno));
  400.     return 1;
  401.     }
  402.  
  403.     amtWritten = write(streamID, (char *) &packet, sizeof(packet));
  404.     if (amtWritten < 0) {
  405.     (void) fprintf(stderr, "Error sending debug packet: %s\n",
  406.         strerror(errno));
  407.     return 1;
  408.     }
  409.     if (amtWritten != sizeof(packet)) {
  410.     (void) fprintf(stderr, "Short write for packet: %d\n", amtWritten);
  411.     return 1;
  412.     }
  413.     return 0;
  414. }
  415.  
  416. /*
  417.  *----------------------------------------------------------------------
  418.  *
  419.  * main --
  420.  *
  421.  *    Main program for "kmsg".
  422.  *
  423.  * Results:
  424.  *    None.
  425.  *
  426.  * Side effects:
  427.  *    Causes things to happen in a target machine.  See the man page
  428.  *    for details.
  429.  *
  430.  *----------------------------------------------------------------------
  431.  */
  432.  
  433. int    getVersion = 0;
  434. int    debug = 0;
  435. int    detach = 0;
  436. char    *versionString = (char *)NULL;
  437. int    reboot = 0;
  438. char    *rebootString = (char *)NULL;
  439.  
  440. Option optionArray[] = {
  441.     {OPT_TRUE, "c", (char *) &detach,
  442.     "Continue the kernel"},
  443.     {OPT_TRUE, "d", (char *) &debug,
  444.     "Force kernel into the debugger"},
  445.     {OPT_TRUE, "r", (char *) &reboot,
  446.     "Reboot the machine using the empty string"},
  447.     {OPT_STRING, "R", (char *) &rebootString,
  448.     "Reboot the machine using the given string"},
  449.     {OPT_STRING, "s", (char *) &versionString,
  450.     "Version string to compare version of kernel to (implies -v)"},
  451.     {OPT_TRUE, "v", (char *) &getVersion,
  452.     "Print out the version of the kernel."},
  453. };
  454.  
  455. main(argc, argv)
  456.     int        argc;
  457.     char    **argv;
  458. {
  459.     StopInfo    stopInfo;
  460.     char    buffer[100];
  461.  
  462.     argc = Opt_Parse(argc, argv, optionArray, Opt_Number(optionArray), 0);
  463.     if (argc != 2) {
  464.     (void) fprintf(stderr, "Usage:  %s [options] hostname\n", argv[0]);
  465.     exit(1);
  466.     }
  467.     if (debug) {
  468.     if (SendDebug(argv[1]) != 0) {
  469.         exit(1);
  470.     }
  471.     }
  472.     netSocket = CreateSocket(argv[1]);
  473.     if (detach) {
  474.     SendCommand(DBG_GET_STOP_INFO, (char *)NULL, (char *)&stopInfo,
  475.             sizeof(stopInfo));
  476. #ifdef sun3
  477.     SendCommand(DBG_DETACH, (char *) &stopInfo.pc, (char *)NULL,
  478.             sizeof(stopInfo.pc));
  479. #else
  480.     SendCommand(DBG_DETACH, (char *) &stopInfo.regs.pc, (char *)NULL,
  481.             sizeof(stopInfo.regs.pc));
  482. #endif /* sun3 */
  483.     }
  484.     if (getVersion || versionString != (char *)NULL) {
  485.     SendCommand(DBG_GET_VERSION_STRING, (char *)0, buffer, 100);
  486.     (void) printf("%s\n", buffer);
  487.     if (versionString != (char *)NULL) {
  488.         exit(strcmp(buffer, versionString));
  489.     }
  490.     }
  491.     if (rebootString != (char *)NULL) {
  492.     SendCommand(DBG_REBOOT, rebootString, (char *)NULL,
  493.             strlen(rebootString));
  494.     } else if (reboot) {
  495.     SendCommand(DBG_REBOOT, (char *)NULL, (char *)NULL, 0);
  496.     }
  497.  
  498.     exit(0);
  499. }
  500.